package cn.itsource.org.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.itsource.basic.config.exception.BusinessException;
import cn.itsource.basic.service.impl.BaseServiceImpl;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.RedisService;
import cn.itsource.basic.util.SendMessageService;
import cn.itsource.org.domain.User;
import cn.itsource.org.mapper.UserMapper;
import cn.itsource.org.pojo.dto.LoginDto;
import cn.itsource.org.pojo.info.LoginInfo;
import cn.itsource.org.pojo.vo.LoginVo;
import cn.itsource.org.query.UserQuery;
import cn.itsource.org.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Service
@Slf4j
//Propagation.SUPPORTS:支持别人事务
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class UserServiceImpl extends BaseServiceImpl<User, UserQuery> implements IUserService {
    //基础查询由继承得到

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SendMessageService sendMessageService;


    @Override
    public AjaxResult checkPhone(String phone) {
        //1.验证手机号合法性
        boolean mobile = Validator.isMobile(phone);
        if (!mobile){
            throw new BusinessException("手机号有误,请重新输入...");
        }

        //2.校验手机号是否被注册过 select * from t_user where phone = #{phone}
        User user = userMapper.findByPhone(phone);

        if (user != null){
            throw new BusinessException("用户已经注册过了...");
        }

        return AjaxResult.createSuccess("手机号验证通过");

    }


    /**
     * 发送验证码
     * @param phone
     * @return
     */
    @Override
    public AjaxResult sendMobileCode(String phone, HttpServletRequest request) {
        //验证手机号
        boolean mobile = Validator.isMobile(phone);
        if (!mobile){
            throw new BusinessException("手机号有误,请重新输入...");
        }

        //2.校验手机号是否被注册过
        User user = userMapper.findByPhone(phone);

        if (user != null){
            throw new BusinessException("用户已经注册过了...");
        }

        //3.拦截同一个ip一直获取验证码  //user/sendMobileCode/177255555554  ip user/sendMobileCode
        //String s = request.getRemoteAddr() + request.getRequestURI();


        /*String res = redisService.getKeyObjectValue(s, String.class);
        if (res != null){ //如果redis里面有数据，代表你访问过于频繁
            throw new BusinessException("哥哥，你太快了...");
        }
        //存ip到redis中,保持1分钟,1分钟内重复获取抛出上面的异常
        redisService.setStringKeyAndValue(s,phone,1);*/

        //4.生成验证码,保存到redis 5分钟
        String code = RandomUtil.randomNumbers(4);
        //phone:手机号  code:验证码
        redisService.setStringKeyAndValue(phone,code,5);
        //[宠物乐园验证码]:1905,手机号:17799996666
        log.info("[宠物乐园验证码]:{},手机号:{}",code,phone);

        //调用发送验证码的服务 打印知道存到redis里面的验证码就行了,不发送
        //sendMessageService.sendPhoneMessage(phone,"[宠物乐园验证码]:"+code);

        return AjaxResult.createSuccess("发送验证码成功");
    }

    @Override
    @Transactional
    public AjaxResult registerUser(User user) {
        //自己去比对两次密码
        if (!StringUtils.equals(user.getPassword(), user.getConfigPassword())) {
            throw new BusinessException("两次密码不一致");
        }

        //验证手机号
        boolean mobile = Validator.isMobile(user.getPhone());
        if (!mobile){
            throw new BusinessException("手机号有误,请重新输入...");
        }

        //2.校验手机号是否被注册过
        User dbUser = userMapper.findByPhone(user.getPhone());

        if (dbUser != null){
            throw new BusinessException("用户已经注册过了...");
        }
        //1.从redis里面获取验证码，如果获取不到，过期了
        String redisCode = redisService.getKeyStringValue(user.getPhone());

        //1.1没拿到异常
        /*if (StrUtil.isBlank(redisCode)){
            throw   new BusinessException("验证码过期了");
        } 这个是全写，下面是java8新写法 */
        Optional.ofNullable(redisCode).orElseThrow(() -> new BusinessException("验证码过期了"));

        //2.把你传递的验证码和redis里面比对，如果比对不过，代表验证码错误
        if (!StrUtil.equals(user.getCode(),redisCode)){
            throw new BusinessException("验证码错误...");
        }

        //3.入库 （注意：加盐加密）
        user.initMd5();
        userMapper.insertSelective(user);

        return AjaxResult.createSuccess();
    }

    @Override
    public AjaxResult login(LoginDto loginDto) {

        //1.根据username匹配user表的数据,如果没有,jd:账户名与密码不匹配，请重新输入
        User dbUser = userMapper.findByUsername(loginDto);
        Optional.ofNullable(dbUser).orElseThrow(() -> new BusinessException("账户名与密码不匹配，请重新输入"));
        //2.对页面传递过来的pwd进行加盐加密
        String pagePwd = MD5.create().setSalt(dbUser.getSalt().getBytes()).digestHex(loginDto.getPassword());

        //3.第二步的密码和数据库的密码串进行比对,如果比对不过 jd:账户名与密码不匹配，请重新输入
        if (!StringUtils.equals(pagePwd,dbUser.getPassword())){
            throw new BusinessException("账户名与密码不匹配，请重新输入");
        }

        //4.存到redis里面,30分钟
        LoginInfo loginInfo = BeanUtil.copyProperties(dbUser, LoginInfo.class);
        loginInfo.setUserId(dbUser.getId());

        String token = IdUtil.fastSimpleUUID();
        redisService.setStringKeyAndValue(token,loginInfo,30);

        LoginVo loginVo = BeanUtil.copyProperties(dbUser, LoginVo.class);
        loginVo.setToken(token);

        //5.返回成功对象,携带token以及用户数据
        return AjaxResult.createSuccess(loginVo);

    }

    public static void main(String[] args) {
        log.info("[宠物乐园验证码]:{},手机号:{}","111","17736565658");//推荐

        log.info("[宠物乐园验证码]:"+"123213"+",手机号:"+"1772135450");
        //[宠物乐园验证码]:111,手机号:17736565658


        boolean equals = StringUtils.equals(null, null);
        System.out.println(equals);

    }


}
